#pragma once

#include <grpcpp/grpcpp.h>
#include "message.grpc.pb.h"
#include "message.pb.h"
#include <queue>
#include <memory>
#include <string>
#include <mutex>
#include <condition_variable>
#include "Singleton.h"



class StatusConPool{
public:
    StatusConPool(std::size_t poolSize,const std::string& host,const std::string& port)
    :poolSize_(poolSize),host_(host),port_(port),b_stop_(false)
    {
        std::shared_ptr<grpc::Channel> channel = ::grpc::CreateChannel(host_+":"+port_,grpc::InsecureChannelCredentials());
        //建立连接
        for (int i = 0; i < poolSize_; i++)
        {
            stubs_.push(message::StatusServer::NewStub(channel));
        }
    }
    ~StatusConPool()
    {
        {
            
            std::unique_lock<std::mutex> lck(mtx_);
            b_stop_ = true;
            cond_.notify_all();
            while (!stubs_.empty())
            {
                stubs_.pop();
            }
        }
        
    }

    //获取连接
    std::unique_ptr<message::StatusServer::Stub> GetConnection()
    {
        std::unique_lock<std::mutex> lock(mtx_);
        cond_.wait(lock,[this](){
            return !stubs_.empty()||b_stop_;
        });

        if(b_stop_)
        {
            return nullptr;
        }
        std::unique_ptr<message::StatusServer::Stub> stub = std::move(stubs_.front());
        stubs_.pop();
        return stub;

    }

    //归还连接
    void ReturnConnection(std::unique_ptr<message::StatusServer::Stub> stub)
    {
        std::unique_lock<std::mutex> lock(mtx_);
        if (b_stop_)
        {
            return;
        }
        stubs_.push(std::move(stub));
        cond_.notify_one();
    }

private:
    std::size_t poolSize_;
    std::string host_;
    std::string port_;
    
    //利用队列存储stub的智能指针
    std::queue<std::unique_ptr<message::StatusServer::Stub>> stubs_;
    std::mutex mtx_;
    std::condition_variable cond_;

    bool b_stop_;
};


class StatusGrpcClient:public Singleton<StatusGrpcClient>
{
    friend class Singleton<StatusGrpcClient>;
public:
    message::LoginResponse Login(int uid,const std::string& token);
    ~StatusGrpcClient()=default;


private:
    StatusGrpcClient();
    std::unique_ptr<StatusConPool> pool_;
};